package com.working.libcommon.adapter

import android.annotation.SuppressLint
import android.view.View
import androidx.lifecycle.*
import androidx.paging.*
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.working.libcommon.exts.doWithTry

//@OptIn(ExperimentalPagingApi::class)
fun <T : IPagingKey, VH : BaseViewHolder<T>> RecyclerView.setPagingAdapter(
    lifecycleOwner: LifecycleOwner,
    pagingAdapter: BasePagingAdapter<T, VH>
) {
    val realAdapter = pagingAdapter.build()
    adapter = realAdapter
    pagingAdapter.fetchData().cachedIn(lifecycleOwner.lifecycleScope).asLiveData()
        .observe(lifecycleOwner, Observer {
            lifecycleOwner.lifecycleScope.launchWhenCreated {
                pagingAdapter.submitData(it)
            }
        })
    val emptyViewEnable = pagingAdapter.emptyViewEnable
    pagingAdapter.emptyViewEnable = false
    pagingAdapter.isDataInitialized.observe(lifecycleOwner) {
        if (it) {
            pagingAdapter.emptyViewEnable = emptyViewEnable
        }
    }
}

@OptIn(ExperimentalPagingApi::class)
abstract class BasePagingAdapter<T : IPagingKey, VH : BaseViewHolder<T>>(
    diffCallback: DiffUtil.ItemCallback<T> = object : DiffUtil.ItemCallback<T>() {
        override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
            return oldItem.getKey() == newItem.getKey()
        }

        @SuppressLint("DiffUtilEquals")
        override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
            return oldItem == newItem
        }

    }
) : PagingDataAdapter<T, VH>(diffCallback) {

    val isDataInitialized = MediatorLiveData<Boolean>().apply {
        postValue(false)
        addSource(dataRefreshFlow.asLiveData()) {
            postValue(true)
        }
    }

    /**
     * 底部的自定义加载状态footer
     *  [LoadStateAdapter]
     */
    open val loadStateFooter: LoadStateAdapter<*> =
        WanFooterAdapter {
            retry()
        }


    private val headerAdapter by lazy {
        DecorateAdapter()
    }

    private val footerAdapter by lazy {
        DecorateAdapter()
    }

    private val emptyAdapter by lazy {
        DecorateAdapter()
    }

    /**
     * @param position
     * @return 当前index在数据源范围内 true
     *  是header footer emptyView
     */
    fun inPaging(position: Int): Boolean {
        val headerCount =
            headerAdapter.itemCount + if (emptyViewEnable) emptyAdapter.itemCount else 0
        return position >= headerCount && position < headerCount + itemCount
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        val manager = recyclerView.layoutManager
        if (manager is GridLayoutManager) {
            manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                override fun getSpanSize(position: Int): Int =
                    if (inPaging(position))
                        1
                    else manager.spanCount
            }
        }
    }


    var emptyViewEnable = true
        set(value) {
            if (field != value)
                if (value) {
                    val index = realAdapter.adapters.indexOf(this)
                    realAdapter.addAdapter(index, emptyAdapter)
                } else realAdapter.removeAdapter(emptyAdapter)
            realAdapter.notifyDataSetChanged()
            field = value
        }

    fun setOnRefreshListener(owner: LifecycleOwner, listener: (LoadState) -> Unit) {
        loadStateFlow.asLiveData()
            .observe(owner, Observer {
                listener.invoke(it.refresh)
            })
    }

    var loadStateEnable = true
        set(value) {
            if (field != value)
                if (value) {
                    val index = realAdapter.adapters.size
                    realAdapter.addAdapter(index, loadStateFooter)
                } else realAdapter.removeAdapter(loadStateFooter)
            realAdapter.notifyDataSetChanged()
            field = value
        }


    abstract val dataSource: PagingDataSource<T>

    lateinit var realAdapter: ConcatAdapter
        private set

    fun fetchData() = dataSource.flow

    internal fun build() =
        ConcatAdapter(headerAdapter, emptyAdapter, this, footerAdapter, loadStateFooter)
            .apply {
                addLoadStateListener(listener)
                realAdapter = this
                addDataRefreshListener {
                    isDataEmpty = it
                    if (it) removeAdapter(
                        loadStateFooter
                    )
                    else if (loadStateEnable) addAdapter(loadStateFooter)
                }

            }

    private val listener: (CombinedLoadStates) -> Unit = { loadStates ->
        if (loadStates.refresh is LoadState.Error || loadStates.append is LoadState.Error) {
            addLoadStateFooterIfNeed()
        }
        if (loadStates.refresh is LoadState.Error) {
            loadStateFooter.loadState = loadStates.refresh
        } else
            loadStateFooter.loadState = loadStates.append
    }

    private fun addLoadStateFooterIfNeed() {
        if (loadStateFooter !in realAdapter.adapters) {
            realAdapter.addAdapter(loadStateFooter)
        }
    }

    var isDataEmpty: Boolean = false
        set(value) {
            field = value
            emptyView?.let {
                if (value) {
                    emptyAdapter.add(it)
                } else {
                    emptyAdapter.remove(it)
                }
            }
        }


    /**
     * 使用emptyView需要支持header
     */
    var emptyView: View? = null
        set(value) {
            when {
                value == null && field == null -> {
                }
                value == null && field != null -> {
                    emptyAdapter.remove(field!!)
                }
                value != null && field == null -> {
                    emptyAdapter.add(value)
                }
                value != null && field != null -> {
                    emptyAdapter.remove(field!!)
                    emptyAdapter.add(value)
                }
            }
            field = value
        }


    /**
     * 添加headerView
     */
    fun addHeaderView(headerView: View): BasePagingAdapter<T, VH> {
        headerAdapter.add(headerView)
        return this
    }

    /**
     * 移除headerView
     */
    fun removeHeaderView(headerView: View) {
        headerAdapter.remove(headerView)
    }
    /**
     * 移除headerView
     */
    fun removeAllHeaderView() {
        headerAdapter.clear()
    }

    /**
     * 添加footerView
     */
    fun addFooterView(footerView: View): BasePagingAdapter<T, VH> {
        footerAdapter.add(footerView)
        return this
    }

    /**
     * 移除footerView
     */
    fun removeFooterView(footerView: View) {
        footerAdapter.remove(footerView)
    }


    override fun onBindViewHolder(holder: VH, position: Int) {
        doWithTry {
            val data = getItem(position)
            data?.let {
                holder.bindData(data, position)
            }
        }

    }
}

